﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Lrd.Template.Core.Infrastructure.Exceptions;

namespace Lrd.Template.Core.Infrastructure.Entity
{
    public class EntityManager : IEntityManager
    {
        private readonly IEntityMappingConfigurationTypeFinder _entityMappingConfigurationTypeFinder;

        public EntityManager(IEntityMappingConfigurationTypeFinder entityMappingConfigurationTypeFinder)
        {
            _entityMappingConfigurationTypeFinder = entityMappingConfigurationTypeFinder;
        }

        private static ConcurrentDictionary<Type, IEntityMappingConfiguration[]> _entityRegistersDict
           = new ConcurrentDictionary<Type, IEntityMappingConfiguration[]>();



        public void Initialize()
        {
            var dict = _entityRegistersDict;
            Type[] types = _entityMappingConfigurationTypeFinder.FindAll(true);
            if (types.Length == 0)
            {
                return;
            }

        
            dict.Clear();
            var groups = types.Select(o => Activator.CreateInstance(o) as IEntityMappingConfiguration).ToList().GroupBy(m => m.DbContextType);
            Type key;
            foreach (var group in groups)
            {
                key = group.Key ?? typeof(DefaultDbContext);
                var list = new List<IEntityMappingConfiguration>();
                if (group.Key == null || group.Key == typeof(DefaultDbContext))
                {
                    list.AddRange(group);
                }
                else
                {
                    list = group.ToList();
                }
                if (list.Count > 0)
                {
                    dict[key] = list.ToArray();
                }

            }
            _entityRegistersDict = dict;


        }


        public IEnumerable<IEntityMappingConfiguration> GetEntityMappingConfigurations(Type dbContextType)
        {
            return _entityRegistersDict.ContainsKey(dbContextType) ? _entityRegistersDict[dbContextType] : Enumerable.Empty<IEntityMappingConfiguration>();
        }

        public Type GetDbContextTypeForEntity(Type entityType)
        {
            var dict = _entityRegistersDict;
            if (dict.Count == 0)
            {
                throw new DomainException($"未发现任何数据上下文实体映射配置，请通过对各个实体继承基类“EntityMappingConfiguration<TEntity, TKey>”以使实体加载到上下文中");
            }

            var key = _entityRegistersDict.Where(o => o.Value.Any(m => m.EntityType == entityType)).FirstOrDefault().Key;
            if (key is null)
            {

                throw new DomainException($"无法获取实体类“{entityType}”的所属上下文类型，请通过继承基类“EntityMappingConfiguration<TEntity, TKey>”配置实体加载到上下文中");
            }
            return key;

        }

    }
}
